package svm_oao;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.StringTokenizer;

import data_access.ResultObj;
import svm_adag.ADAG;
import svm_ddag.DDAG;
import libsvm.svm;
import libsvm.svm_model;
import libsvm.svm_node;
import libsvm.svm_parameter;

public class SVMPredict {

	public static String predict(BufferedReader input, DataOutputStream output, svm_model model,
			int predict_probability, int type, ResultObj obj) throws IOException {
		int correct = 0;
		int total = 0;
		double error = 0;
		double sumv = 0, sumy = 0, sumvv = 0, sumyy = 0, sumvy = 0;

		int svm_type = svm.svm_get_svm_type(model);
		int nr_class = svm.svm_get_nr_class(model);
		double[] prob_estimates = null;

		if (predict_probability == 1) {
			if (svm_type == svm_parameter.EPSILON_SVR || svm_type == svm_parameter.NU_SVR) {
				System.out.println("Prob. model for test data: target value = predicted value"
						+ "z,\nz: Laplace distribution e^(-|z|/sigma)/(2sigma),sigma="
						+ svm.svm_get_svr_probability(model) + "\n");
			} else {
				int[] labels = new int[nr_class];
				svm.svm_get_labels(model, labels);
				prob_estimates = new double[nr_class];
				output.writeBytes("labels");
				for (int j = 0; j < nr_class; j++)
					output.writeBytes(" " + labels[j]);
				output.writeBytes("\n");
			}
		}
		while (true) {
			String line = input.readLine();
			if (line == null)
				break;

			StringTokenizer st = new StringTokenizer(line, " \t\n\r\f:");

			double target = atof(st.nextToken());
			int m = st.countTokens() / 2;
			svm_node[] x = new svm_node[m];
			for (int j = 0; j < m; j++) {
				x[j] = new svm_node();
				x[j].index = atoi(st.nextToken());
				x[j].value = atof(st.nextToken());
			}

			double v;
			if (predict_probability == 1 && (svm_type == svm_parameter.C_SVC || svm_type == svm_parameter.NU_SVC)) {
				v = svm.svm_predict_probability(model, x, prob_estimates);
				output.writeBytes(v + " ");
				for (int j = 0; j < nr_class; j++)
					output.writeBytes(prob_estimates[j] + " ");
				output.writeBytes("\n");
			} else {
				if (type == 1) {
					v = svm.svm_predict(model, x);
				} else if (type == 2) {
					v = DDAG.ddag_predict(model, x);
				} else {
					v = ADAG.adag_predict(model, x);
				}
				output.writeBytes(v + "\n");
			}

			if (v == target)
				++correct;
			error += (v - target) * (v - target);
			sumv += v;
			sumy += target;
			sumvv += v * v;
			sumyy += target * target;
			sumvy += v * target;
			++total;
		}
		if (svm_type == svm_parameter.EPSILON_SVR || svm_type == svm_parameter.NU_SVR) {
			System.out.println("Mean squared error = " + error / total + " (regression)\n");
			System.out.println("Squared correlation coefficient = "
					+ ((total * sumvy - sumv * sumy) * (total * sumvy - sumv * sumy))
					/ ((total * sumvv - sumv * sumv) * (total * sumyy - sumy * sumy)) + " (regression)\n");
			return "";
		} else {
			if (total == 0) {
				return "error";
			}
			double acc = (double) correct / total * 100;

			String accuracy = (double) Math.round(acc * 100) / 100 + "% (" + correct + "/" + total + ")";
			System.out.println("Accuracy = " + accuracy + " (classification)\n");
			if (type == 1) {
				obj.setAccOAO((double) Math.round(acc * 100) / 100);
				obj.setClassNumber(model.nr_class);
				obj.setTestingSize(total);
			} else if (type == 2) {
				obj.setAccDDAG((double) Math.round(acc * 100) / 100);
			} else {
				obj.setAccADAG((double) Math.round(acc * 100) / 100);
			}
			return accuracy;
		}
	}

	private static double atof(String s) {
		return Double.valueOf(s).doubleValue();
	}

	private static int atoi(String s) {
		return Integer.parseInt(s);
	}
}
